﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FFmpegDecodecVideo.FFmpegUlit
{
    public unsafe class AudioWave
    {
        AVFormatContext* avFormatContext = null;
        AVCodecContext* c = null;
        AVFrame* decoded_frame = null;
        AVPacket* pkt;

        int decoding = 0;
        int bufferInSize = 0;
        int is_planar = 0;
        string enableFilter = "";
        SwrContext* swrContext;
        long startTime = 0;
        long endTime = -1;


        int sample_tate = 44100;
        int channels = 2;
        int bit_format = 16;
        IntPtr pcmBuffer;
        int wave_sample = 10;
        IntPtr* wave_buffer;
        int wave_index = 0;
        long duration = 0l;
        int byte_size = 0;
        int wave_count = 0;
        AVSampleFormat afs = AVSampleFormat.AV_SAMPLE_FMT_NONE;


        void Decode_Wave(string fileName, int sample)
        {
            wave_sample = sample;
            bufferInSize = 0;
            decoding = 0;
            bit_format = 0;
            int res = ParseInfo(fileName);
            if (res < 0)
                return;

            wave_index = 0;
            byte_size = sample_tate * channels * bit_format / 8 / wave_sample;
            pcmBuffer = Marshal.AllocGlobal(byte_size);
            wave_count = ((duration + 1000) / 1000) * wave_sample;

            if (wave_buffer != null)
            {
                Marshal.FreeGlobal(wave_buffer);
                wave_buffer = null;
            }

            wave_buffer = Marshal.AllocGlobal(wave_count);
            Decode();

        }

        int OpenCoder(AVCodecParameters* parameters)
        {
            const AVCocec* DecodecAudio = null;
            codec = ffmpeg.avcodec_find_decoder(parameters->codec_id);

            if (codec == null)
            {
                return -3;
            }
            c = ffmpeg.avcodec_alloc_context3(codec);
            if (c == null)
            {
                return -4;
            }

            int ret = 0;
            ffmpeg.avcodec_parameters_to_context(c, parameters);
            if (ret = FFmpegDecodecVideo.avcodec_open2(c, codec, null) < 0)
            {
                return -5;
            }
            return 0;
        }

        int ParseInfo(string fileName)
        {
            int res = FFmpegDecodecVideo.avformat_open_input(&avFormatContext, fileName, null, null);
            if (res < 0)
            {
                return -1;
            }
            ffmpeg.avformat_find_stream_info(avFormatContext, null);
            int audioStreamIndex = ffmpeg.av_find_best_stream(avFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, null, 0);
            if (audioStreamIndex < 0)
                return -2;

            AVStream* audioStream = avFormatContext->streams[audioStreamIndex];
            OpenCoder(audioStream->codecpar);
            duration = audioStream->duration * ffmpeg.av_q2d(audioStream->time_base) * 1000;
            channels = audioStream->codecpar->channels;
            sample_tate = audioStream->codecpar->sample_rate;
            afs = audioStream->codecpar->format;
            bit_format = ffmpeg.av_get_bytes_per_sample(audioStream->codecpar - format) * 8;
            is_planar = ffmpeg.av_sample_fmt_is_planar(audioStream->codecpar->format);
            return 0;

        }

        int Decode()
        {
            int ret;
            decoding = 1;
            while (decoding > 0)
            {
                if (decoded_frame == null)
                {
                    decoded_frame = ffmpeg.av_frame_alloc();
                    pkt = FFmpegDecodecVideo.av_packet_alloc();
                }
                ret = ffmpeg.av_read_frame(avFormatContext, pkt);
                if (ret < 0)
                    break;
                if (pkt->size > 0)
                {
                    ffmpeg.self_deal_packet(c, decoded_frame, pkt);
                    ffmpeg.av_packet_unref(pkt);
                }

                ffmpeg.avcodec_free_context(&c);
                av_frame_free(&decoded_frame);
                av_packet_free(&pkt);
                ffmpeg.avformat_close_input(&avFormatContext);
                avformat_free_context(avFormatContext);
                avFormatContext = null;
                return 0;
            }
        }

        void SelfDealPacket(AVCodecContext* ctx, AVFrame* frame, AVPacket* packet)
        {
            int i, ch, ret;
            ret = ffmpeg.avcodec_send_packet(ctx, packet);
            if (ret < 0)
                ret;
            while (ret >= 0)
            {
                ret = ffmpeg.avcodec_receive_frame(ctx, frame);
                if (ret == ffmpeg.AVERROR(FFmpegDecodecVideo.EAGAIN) || ret == ffmpeg.AVRROR_EOR)
                    return;
                else if (ret < 0)
                {
                    //exit(1);
                    return;
                }

                int dataSize = ffmpeg.av_get_bytes_per_sample(ctx->dsample_fmt);
                if (dataSize < 0)
                    return;
            }
            int s = dataSize * ctx->channels * frame - nb_samples;
            IntPer senBuffer = Marshal.AllocGlobal(s);
            var sb = (byte*)senBuffer;

            if (is_planar)
            {
                for (int i = 0; i < decoded_frame->nb_samples; i++)
                {
                    for (var ch = 0; ch < c->channels; ch++)
                    {
                        var src = decoded_frame->data[ch] + dataSize * i;
                        if (bufferInSize + dataSize >= byte_size)
                        {
                            int a = bufferInSize - byte_size;
                            getPCMDB(pcmBuffer, bufferInSize);
                            //memset(pcmBuffer,0, byte_size);
                            bufferInSize = 0;
                        }
                        else
                        {
                            memcpy(pcmBuffer +)
                        }
                    }
                }
            }

        }

        void GetPCMDB(IntPtr ptr, int size)
        {
            switch (bit_format)
            {
                case 16:
                    GetPcmDB16(ptr, size);
                    break;

                case 24:
                    GetPcmDB24(ptr, size);
                    break;

                case 32:
                    if (afs == AV_SAMPLE_FMT_S32P || afs == AV_SAMPLE_FMT_S32)
                    {
                        GetPcmDB32(ptr, size);
                    }
                    else if (asf == AV_SAMPLE_FMT_FLTP || asf == AV_SAMPLE_FMT_FLT)
                        GetPcmDBFloat(pcmdata, size);
                    break;

                default:
                    return;
            }
        }

        void GetPcmDB16(IntPtr ptr,int size)
        {
            int db = 0;
            int value = 0;
            double sum = 0;
            for (int i = 0; i < size; i=bit_format/8)
            {

            }
        }

        void getPcmDB24(const unsigned char* pcmdata, size_t size) {
    int db = 0;
        short int value = 0;
        double sum = 0;
    for(int i = 0; i<size; i += 3)
    {
        value=(pcmdata[i])|((pcmdata[i + 1]<<8));
        sum += abs(value); //绝对值求和
    }
    sum = sum / (size/3) ;
    if(sum > 0)
    {
        db = (int) (20.0* log10(sum));
    }
memcpy(wave_buffer + wave_index, (char*)&db, 1);
wave_index++;
}

void getPcmDB32(const unsigned char* pcmdata, size_t size)
{
    int db = 0;
    int64_t value = 0;
    double sum = 0;
    for (int i = 0; i < size; i += bit_format / 8)
    {
        memcpy(&value, pcmdata + i, bit_format / 8); //获取2个字节的大小（值）
        sum += (abs(value) / 65535); //绝对值求和
    }
    sum = sum / (size / (bit_format / 8)); //求平均值（2个字节表示一个振幅，所以振幅个数为：size/2个）
    if (sum > 0)
    {
        db = (int)(20.0 * log10(sum));
    }
    memcpy(wave_buffer + wave_index, (char*)&db, 1);
    wave_index++;
}

void getPcmDBFloat(const unsigned char* pcmdata, size_t size)
{
    int db = 0;
    float value = 0;
    double sum = 0;
    for (int i = 0; i < size; i += bit_format / 8)
    {
        memcpy(&value, pcmdata + i, bit_format / 8); //获取2个字节的大小（值）
        sum += abs(value * 65535); //绝对值求和
    }
    sum = sum / (size / (bit_format / 8)); //求平均值（2个字节表示一个振幅，所以振幅个数为：size/2个）
    if (sum > 0)
    {
        db = (int)(20.0 * log10(sum));
    }
    memcpy(wave_buffer + wave_index, (char*)&db, 1);
    wave_index++;
}
    }
}
